package com.auto.printer.common.restful;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.auto.printer.common.annoation.FieId;
import com.auto.printer.common.exception.ErrorCode;
import com.auto.printer.common.impl.BaseControllerService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.google.common.collect.Maps;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangjie
 * @date 2022年02月09日 9:55
 * @description controller基类
 */
@Component
public class BaseController {
//
//    @Autowired
//    private BaseControllerService baseControllerService;

    protected ResultModel toResult() {
        return toResult(null, "请求成功", 200);
    }

    protected ResultModel toResult(boolean b) {
        if (b) {
            return toResult();
        }
        return toErrorResult();
    }


    /**
     * 让注解FieId生效，需要指定class
     *
     * @param data
     * @param c
     * @return
     */
    protected ResultModel toResult(Object data, Class c) {

        return toResult(data, "请求成功", 200, c);
    }

    protected ResultModel toResult(Object data, Class c, boolean showTitle) {

        return toResult(data, "请求成功", 200, c, showTitle);
    }

    protected ResultModel toResult(Object data) {

        return toResult(data, "操作成功", 200);
    }

    protected ResultModel toErrorResult() {
        return new ResultModel<Object>(1100, "操作失败", 0L, new LinkedList<>(), null);
    }

    protected ResultModel toErrorResult(int code,String message) {
        return new ResultModel<Object>(code, message, 0L, new LinkedList<>(), null);
    }

    protected ResultModel toErrorResult(String message) {
        return new ResultModel<Object>(1100, message, 0L, new LinkedList<>(), null);
    }
    protected ResultModel toErrorResult(ErrorCode errorCode) {
        return new ResultModel<Object>(errorCode.getCode(), errorCode.getDesc(), 0L, new LinkedList<>(), null);
    }
    protected ResultModel toResult(Object data, String message, int code, Class c) {
        return toResult(data, message, code, c, true);
    }

    /**
     * crm
     *
     * @param data
     * @param message
     * @return
     */
    protected ResultModel toResult(Object data, String message, int code, Class c, boolean showTitle) {
        String[] zero = new String[0];
        ResultModel<Object> objectResultModel = new ResultModel<>();
        //设置title
        LinkedList<Dto> linkedList = new LinkedList<>();

        getFields(c, linkedList);

        linkedList = linkedList.stream().sorted(Comparator.comparing(Dto::getNumber))
                .collect(Collectors.toCollection(LinkedList::new));


        if (showTitle) {
            List<ResultModel.ColumnVo> title = linkedList.stream().map(f -> {
                ResultModel.ColumnVo columnVo = new ResultModel.ColumnVo();

                columnVo.setLabel(f.getMsg());
                columnVo.setProp(f.getName());
                columnVo.setWidth(f.getWidth());
                return columnVo;
            }).collect(Collectors.toList());
            objectResultModel.setColumns(title);
        }

        Map<String, Dto> collectDto = linkedList.stream()
                .filter(f -> {
                    return CollUtil.isNotEmpty(f.getDictValue());
                })
                .distinct()
                .collect(Collectors.toMap(Dto::getName, f -> f));
        objectResultModel.setCode(code);
        if (code < 300) {
            if (data instanceof Page) {
                Page page = (Page) data;

                objectResultModel.setTotal(page.getTotal());
                if (page.getRecords() == null) {
                    objectResultModel.setData(zero);
                } else {
                    List records = page.getRecords();
                    //没有主动配置class
                    if (CollUtil.isEmpty(linkedList)) {
                        objectResultModel.setData(records);
                    } else {

                        List<HashMap<String, Object>> mapList = new ArrayList<>();

                        for (Object record : records) {
                            LinkedHashMap<String, Object> hashMap = Maps.newLinkedHashMapWithExpectedSize(linkedList.size());
                            LinkedHashMap<String, Object> hashMapDat = Maps.newLinkedHashMapWithExpectedSize(
                                    linkedList.size());
                            getFieldsValue(record, record.getClass(), hashMap, linkedList, collectDto);

                            List<String> collect = linkedList.stream()
                                    .sorted(Comparator.comparing(Dto::getNumber))
                                    .map(Dto::getName).collect(Collectors.toList());
                            for (String s : collect) {
                                hashMapDat.put(s, hashMap.get(s));
                            }
                            mapList.add(hashMapDat);
                        }
                        objectResultModel.setData(mapList);
                    }
                }

            } else if (data instanceof Collection) {
                Collection list = (Collection) data;
                objectResultModel.setTotal((long) list.size());
                //放置无法正常返回单纯的列表
                if (CollUtil.isEmpty(linkedList)) {
                    objectResultModel.setData(list);
                } else {
                    List<HashMap<String, Object>> mapList = new ArrayList<>();

                    for (Object record : list) {
                        LinkedHashMap<String, Object> hashMap = Maps.newLinkedHashMapWithExpectedSize(linkedList.size());
                        //hashMap 排序
                        LinkedHashMap<String, Object> hashMapDat = Maps.newLinkedHashMapWithExpectedSize(linkedList.size());
                        getFieldsValue(record, record.getClass(), hashMap, linkedList, collectDto);

                        for (Dto s : linkedList) {
                            hashMapDat.put(s.getName(), hashMap.get(s.getName()));
                        }
                        mapList.add(hashMapDat);
                    }
                    objectResultModel.setData(mapList);
                }


            } else {
                objectResultModel.setTotal(1L);
                objectResultModel.setData(data);
            }
        }

        objectResultModel.setMessage(message);

        return objectResultModel;
    }

    protected ResultModel toResult(Object data, String message, int code) {

        return toResult(data, message, code, null);
    }

    /**
     * 两个结果返回
     *
     * @param data
     * @param otherData
     * @param message
     * @param code
     * @param c
     * @return
     */
    protected ResultModel toResultData(Object data, Object otherData, String message, int code, Class c, boolean showTitle) {

        String[] zero = new String[0];
        ResultModel<Object> objectResultModel = new ResultModel<>();
        //设置title
        LinkedList<Dto> linkedList = new LinkedList<>();

        getFields(c, linkedList);

        linkedList = linkedList.stream().sorted(Comparator.comparing(Dto::getNumber))
                .collect(Collectors.toCollection(LinkedList::new));

        List<ResultModel.ColumnVo> title = linkedList.stream().map(f -> {
            ResultModel.ColumnVo columnVo = new ResultModel.ColumnVo();

            columnVo.setLabel(f.getMsg());
            columnVo.setProp(f.getName());
            columnVo.setWidth(f.getWidth());
            return columnVo;
        }).collect(Collectors.toList());

        Map<String, Dto> collectDto = linkedList.stream()
                .filter(f -> {
                    return CollUtil.isNotEmpty(f.getDictValue());
                })
                .distinct()
                .collect(Collectors.toMap(Dto::getName, f -> f));
        if (showTitle) {
            objectResultModel.setColumns(title);
        }
        objectResultModel.setColumns(title);

        objectResultModel.setCode(code);
        if (code < 300) {
            if (data instanceof Page) {
                Page page = (Page) data;

                objectResultModel.setTotal(page.getTotal());
                if (page.getRecords() == null) {
                    objectResultModel.setData(zero);
                } else {
                    List records = page.getRecords();
                    //放置无法正常返回单纯的列表
                    if (CollUtil.isEmpty(linkedList)) {
                        objectResultModel.setData(records);
                    } else {
                        List<HashMap<String, Object>> mapList = new ArrayList<>();
                        for (Object record : records) {
                            LinkedHashMap<String, Object> hashMap = Maps.newLinkedHashMapWithExpectedSize(title.size());
                            LinkedHashMap<String, Object> hashMapDat = Maps.newLinkedHashMapWithExpectedSize(
                                    title.size());
                            getFieldsValue(record, record.getClass(), hashMap, linkedList, collectDto);
                            //字段
                            List<String> collect = linkedList.stream()
                                    .sorted(Comparator.comparing(Dto::getNumber))
                                    .map(Dto::getName).collect(Collectors.toList());
                            for (String s : collect) {
                                hashMapDat.put(s, hashMap.get(s));
                            }
                            mapList.add(hashMapDat);
                        }

                        objectResultModel.setData(mapList);
                    }

                }

            } else if (data instanceof Collection) {
                Collection list = (Collection) data;
                objectResultModel.setTotal((long) list.size());
                if (CollUtil.isEmpty(linkedList)) {
                    //放置无法正常返回单纯的列表
                    objectResultModel.setData(list);
                } else {
                    List<HashMap<String, Object>> mapList = new ArrayList<>();
                    for (Object record : list) {
                        LinkedHashMap<String, Object> hashMap = Maps.newLinkedHashMapWithExpectedSize(title.size());
                        //hashMap 排序
                        LinkedHashMap<String, Object> hashMapDat = Maps.newLinkedHashMapWithExpectedSize(title.size());
                        getFieldsValue(record, record.getClass(), hashMap, linkedList, collectDto);

                        List<String> collect = linkedList.stream()
                                .sorted(Comparator.comparing(Dto::getNumber))
                                .map(Dto::getName).collect(Collectors.toList());
                        for (String s : collect) {
                            hashMapDat.put(s, hashMap.get(s));
                        }
                        mapList.add(hashMapDat);
                    }

                    objectResultModel.setData(mapList);
                }
            } else {
                objectResultModel.setTotal(1L);
                objectResultModel.setData(data);
            }
        }

        objectResultModel.setMessage(message);

        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("rows", objectResultModel.getData());
        hashMap.put("otherData", otherData);
        objectResultModel.setData(hashMap);
        return objectResultModel;
    }

    /**
     * 获取要显示的字段值
     *
     * @param o       对象
     * @param c       对象类
     * @param hashMap 值
     * @param dtoList 需要的字段
     */
    private void getFieldsValue(Object o, Class c, HashMap<String, Object> hashMap, List<Dto> dtoList, Map<String, Dto> collect) {

        if (o != null && c != null) {

            Class<?> aClass = o.getClass();

            Field[] fields = c.getDeclaredFields();

            for (Field f : fields) {
                f.setAccessible(true);
                String name = f.getName();
                Class<?> type = f.getType();

                int modifiers = f.getModifiers();
                String modifierString = Modifier.toString(modifiers);

                if (modifierString.contains("static") || modifierString.contains("final") || modifierString.contains(
                        "transient")) {
                    continue;
                }

                try {
                    FieId annotation = f.getAnnotation(FieId.class);
                    if (annotation != null && !annotation.value()) {
                        continue;
                    }
//                    String value = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
//                    Method method = aClass.getMethod(value);


                    //时间处理
                    if (type == Date.class) {
                        JsonFormat jsonFormat = f.getAnnotation(JsonFormat.class);

                        if (annotation != null && !StrUtil.isBlankIfStr(annotation.pattern())) {
                            String valueType = annotation.pattern();
                            Date invoke = (Date) ReflectUtil.getFieldValue(o, f);
                            String format = DateUtil.format(invoke, valueType);
                            //保存值
                            hashMap.put(name, format);
                            break;
                        } else if (jsonFormat != null && !StrUtil.isBlankIfStr(jsonFormat.pattern())) {
                            String valueType = jsonFormat.pattern();
                            Date invoke = (Date) ReflectUtil.getFieldValue(o, f);
                            String format = DateUtil.format(invoke, valueType);
                            //保存值
                            hashMap.put(name, format);
                            break;
                        }
                    }
                    Object invoke = ReflectUtil.getFieldValue(o, f);
                    if (collect.containsKey(name)) {
                        Map<String, String> dictValue = collect.get(name).getDictValue();
                        //保存值
                        hashMap.put(name + "DictValue", dictValue.getOrDefault(StrUtil.toString(invoke), ""));
                    }
                    //保存值
                    hashMap.putIfAbsent(name, invoke);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            getFieldsValue(o, c.getSuperclass(), hashMap, dtoList, collect);
        }

    }

    /**
     * @param c          对象类
     * @param linkedList 表头
     */
    private void getFields(Class c, LinkedList<Dto> linkedList) {

        if (c != null && !c.equals(Object.class)) {
            Field[] field = c.getDeclaredFields();
            if (field.length <= 0) {
                return;
            }
            for (Field fie : field) {
                if (!fie.isAccessible()) {
                    fie.setAccessible(true);
                }
                int modifiers = fie.getModifiers();
                String modifierString = Modifier.toString(modifiers);

                if (modifierString.contains("static") || modifierString.contains("final") || modifierString.contains(
                        "transient")) {
                    continue;
                }

                //扫描注解
                FieId annotation = fie.getAnnotation(FieId.class);
//                ApiModelProperty apiModelProperty = fie.getAnnotation(ApiModelProperty.class);
                String name = fie.getName();
                String msg = fie.getName();
//                //跟注解的默认值要对应，否则会影响排序
                int number = 9999;
                boolean show = true;
//                if (apiModelProperty != null && !StrUtil.isBlankIfStr(apiModelProperty.value())) {
//                    msg = apiModelProperty.value();
//                }
                if (annotation != null) {
                    if (!StrUtil.isBlankIfStr(annotation.msg())) {
                        msg = annotation.msg();
                    }
                    if (!StrUtil.isBlankIfStr(annotation.name())) {
                        name = annotation.name();
                    }

                    number = annotation.number();

                    show = annotation.value();

                }

                if (show) {
                    Dto dto = new Dto();
                    dto.setMsg(msg);
                    dto.setNumber(number);
                    dto.setName(name);
                    Class<?> type = fie.getType();
                    //时间处理
                    if (type == Date.class) {
                        dto.setWidth("160");
                    } else if (type == LocalDateTime.class) {
                        dto.setWidth("160");
                    }else if (type == LocalDate.class) {
                        dto.setWidth("100");
                    }

                    if(annotation != null && !StrUtil.isBlankIfStr(annotation.width()))
                    {
                        dto.setWidth(annotation.width());
                    }

                    if (annotation != null && !StrUtil.isBlankIfStr(annotation.dictJson())) {
                        String dictJson = annotation.dictJson();
                        if (JSONUtil.isTypeJSON(dictJson)) {
                            HashMap<String, String> hashMap = new HashMap<>();
                            JSONObject object = JSONUtil.parseObj(dictJson);
                            for (Map.Entry<String, Object> entry : object) {
                                hashMap.put(entry.getKey(), StrUtil.toString(entry.getValue()));
                            }
                            dto.setDictValue(hashMap);
                        }
                    }

//                    if (annotation != null && !StrUtil.isBlankIfStr(annotation.dictKey())) {
//                        Map<String, String> sysDictData = baseControllerService
//                                .getSysDictData(annotation.dictKey());
//
//                        if (CollUtil.isNotEmpty(sysDictData)) {
//                            Map<String, String> dictValue = dto.getDictValue();
//                            dictValue.putAll(sysDictData);
//                            dto.setDictValue(dictValue);
//                        }
//                    }
                    linkedList.add(dto);
                    /**
                     * 为字典添加一个新的字段 DictValue
                     */
                    if (CollUtil.isNotEmpty(dto.getDictValue())) {
                        Dto dtoDict = new Dto();
                        BeanUtils.copyProperties(dto, dtoDict);
                        dtoDict.setName(dto.getName() + "DictValue");
                        linkedList.add(dtoDict);
                    }
                }
            }
            getFields(c.getSuperclass(), linkedList);
        }

    }


    static class Dto {

        private String msg;

        private String name;

        private Integer number;

        private String width;
        /**
         * 字典值
         */
        private Map<String, String> dictValue = new HashMap<>();

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getNumber() {
            return number;
        }

        public void setNumber(Integer number) {
            this.number = number;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }

        public Map<String, String> getDictValue() {
            return dictValue;
        }

        public void setDictValue(Map<String, String> dictValue) {
            this.dictValue.putAll(dictValue);
        }


        public String getWidth() {
            return width;
        }

        public void setWidth(String width) {
            this.width = width;
        }
    }
}
